#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "syscall.h"
#include "module.h"
#include "flash.h"
#include "crypto.h"
#include "device.h"
#include "utility.h"
#include "kernel.h"
#include "modmana.h"
#include "sys_info.h"
#include "clk.h"
#include "prn_drv.h"
#include "config.h"
#include "autoconfig.h"
#include "lcd_attr.h"
#include <sys/err.h>

part_t * get_sys_mods_by_name(char * name, uint32_t add,
                uint32_t base, uint32_t size);

static const uint8_t rsa_e[] = {0x01, 0x00, 0x01};

int decode_signature(uint8_t * sig, headinfo_t* app, module_t * pmod)
{
        R_RSA_PUBLIC_KEY publicKey;
        uint8_t mod[MAX_RSA_MODULUS_LEN];
        headinfo_t * phd = (headinfo_t *)mod;
        uint32_t outlen;

        memset(&publicKey,0,sizeof(R_RSA_PUBLIC_KEY));
        publicKey.bits = 2048;

        read_vendor_pk(mod);
        memcpy(publicKey.modulus,mod,MAX_RSA_MODULUS_LEN);
        memcpy(&publicKey.exponent[MAX_RSA_MODULUS_LEN - 3],rsa_e,3);

        RSAPublicDecrypt(mod, &outlen, sig, MAX_RSA_MODULUS_LEN, &publicKey);

        if(phd->head != 0xCC)
                return -1;
        if(phd->hash_flag != 0x2)
                return -1;
        if(phd->public_key != 0x1)
                return -1;
        if(phd->end != 0xCF)
                return -1;

        memcpy(app, phd, sizeof(headinfo_t));

        if (pmod && (phd->firmware_type & (PART_TYPE_MOD >> 8))) {
                memcpy(pmod, mod + sizeof (headinfo_t), sizeof (module_t));
        }
        return 0;
}


int decode_sys_signature(uint8_t * sig, sysheadinfo_t* app)
{
        R_RSA_PUBLIC_KEY publicKey;
        uint32_t outlen;
		uint8_t mod[MAX_RSA_MODULUS_LEN];
        memset(&publicKey,0,sizeof(R_RSA_PUBLIC_KEY));
        publicKey.bits = 2048;

        read_vendor_pk(mod);
        memcpy(publicKey.modulus,mod,MAX_RSA_MODULUS_LEN);
        memcpy(&publicKey.exponent[MAX_RSA_MODULUS_LEN - 3],rsa_e,3);

        rsapublicfunc((uint8_t *)app, &outlen, sig, MAX_RSA_MODULUS_LEN, &publicKey);

	if(memcmp(app->magc, "WITSISOC", 8) != 0)
		return -1;

        return 0;
}


int verify_sysfirmware(part_t * ppart)
{
        uint8_t rsa_header[MAX_RSA_MODULUS_LEN];
        sysheadinfo_t app;
        uint32_t rlen, offset = 0,read_len = 0;

		debug_aux( "Enter into %s()\r\n verify:%s\r\n", __FUNCTION__, ppart->name );
        part_read(ppart, 0, rsa_header, MAX_RSA_MODULUS_LEN);

        if (decode_sys_signature(rsa_header, &app) < 0) {
                return 0;
        }
		debug_aux_hex( "sysheadinfo_t:", &app, sizeof( app ) );
		
        rlen = app.length;
        offset = MAX_RSA_MODULUS_LEN;

        sha2_starts(0);
         while (rlen) {
                read_len = rlen > MAX_RSA_MODULUS_LEN ?
                                MAX_RSA_MODULUS_LEN : rlen;
                if (part_read(ppart, offset, rsa_header, read_len)!= read_len) {
                        return 0;
                }
                sha2_update((uint8_t *)rsa_header, read_len);
                offset += read_len;
                rlen -= read_len;
        }
        sha2_finish(rsa_header);
		debug_aux_hex( "rsa_header:", rsa_header, 32 );
		debug_aux_hex( "app.sha256:", app.sha256, 32 );
		
        if(memcmp(app.sha256, rsa_header, 32)) return 0;
		
        return 1;
}


int verify_firmware3(char * file_name, module_t *pmod, headinfo_t *papp)
{
        uint8_t rsa_header[MAX_RSA_MODULUS_LEN];
        headinfo_t app;
        uint32_t rlen, read_len = 0;

        int fd = open(file_name, O_RDONLY);
        if (fd < 0) return 0;
        if (read(fd, rsa_header, MAX_RSA_MODULUS_LEN) != MAX_RSA_MODULUS_LEN)
                goto end;
        if (decode_signature(rsa_header, &app, pmod) < 0) {
                goto end;
        }
        sha2_starts(0);
        sha2_update((uint8_t *)&app.hash_flag, MODULE_SHA256_LEN);
        rlen = app.length;
        while (rlen) {
                read_len = rlen > MAX_RSA_MODULUS_LEN ?
                                MAX_RSA_MODULUS_LEN : rlen;
                if (read(fd, rsa_header, read_len) != read_len) {
                        goto end;
                }
                sha2_update((uint8_t *)rsa_header, read_len);
                rlen -= read_len;
        }
        sha2_finish(rsa_header);

        if(memcmp(app.sha256, rsa_header, 32)) goto end;
        close(fd);
		memcpy(papp, &app, sizeof(headinfo_t));
        return (app.length+MAX_RSA_MODULUS_LEN);
end:
        close(fd);
        return 0;
}

int verify_firmware2(part_t * ppart)
{
        uint8_t rsa_header[MAX_RSA_MODULUS_LEN];
        headinfo_t app;
        uint32_t rlen, offset = 0,read_len = 0;

		debug_aux( "Enter into %s()\r\n verify:%s\r\n", __FUNCTION__, ppart->name );
        part_read(ppart, 0, rsa_header, MAX_RSA_MODULUS_LEN);
        if (decode_signature(rsa_header, &app, NULL) < 0) {
                return 0;
        }
        if (app.firmware_type != (ppart->flags >> 8)) return 0;

        rlen = app.length;
        offset = MAX_RSA_MODULUS_LEN;

        sha2_starts(0);
        sha2_update((uint8_t *)&app.hash_flag, MODULE_SHA256_LEN);

        while (rlen) {
                read_len = rlen > MAX_RSA_MODULUS_LEN ?
                                MAX_RSA_MODULUS_LEN : rlen;
                if (part_read(ppart, offset, rsa_header, read_len)!= read_len) {
                        return 0;
                }
                sha2_update((uint8_t *)rsa_header, read_len);
                offset += read_len;
                rlen -= read_len;
        }
        sha2_finish(rsa_header);

        if(memcmp(app.sha256, rsa_header, 32)) {
            return 0;
        }

        return 1;
}
int verify_firmware(char * name)
{
        part_t * ppart;
        if (name == NULL) return 0;
        if ((ppart = get_part_by_name(name, NULL)) == NULL) {
                if ((ppart = get_sys_mods_by_name(name, 0, 0, 0)) == NULL)
                        return 0;
        }
		if(ppart->flags & PART_TYPE_SYS)
		    return verify_sysfirmware(ppart);
		else
        	return verify_firmware2(ppart);
}
int empty_fn(void)
{
    return -ENXIO;
}

int lcd_set_attribute(uint8_t atr, void * arg)\
    __attribute__ ((weak, alias("empty_fn")));

void lcd_backlight(uint32_t onoff)\
    __attribute__ ((weak, alias("empty_fn")));
void lcd_clrscr(void)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_disp_img(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t * img)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_disp_string(uint32_t x, uint32_t y, char * string)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_disp_hline(uint32_t x, uint32_t y, uint32_t w)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_disp_vline(uint32_t x, uint32_t y, uint32_t h)\
    __attribute__ ((weak, alias("empty_fn")));


int lcd_get_type(void) \
    __attribute__((weak, alias("empty_fn")));
int lcd_push(void)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_pop(void)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_clrscr_line(uint32_t start_y, uint32_t end_y)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_goto_xy(uint32_t x, uint32_t y)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_get_xy(uint32_t *px, uint32_t *py)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_set_view_port(uint32_t x, uint32_t y, uint32_t w, uint32_t h)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_get_view_port(uint32_t *px, uint32_t *py, uint32_t *pw, uint32_t *ph)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_printf(const char *fmt, ...)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_set_font(lcd_font_type_em emtype)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_set_space(uint32_t wspace, uint32_t hspace)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_get_size(uint32_t * pwidth, uint32_t * pheight)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_set_contrast(uint32_t contrast)\
    __attribute__ ((weak, alias("empty_fn")));
int lcd_statusbar(lcd_statusbar_em  new_flag, lcd_statusbar_em  *pold_flag)\
    __attribute__ ((weak, alias("empty_fn")));
void lcd_putch(char ch, char **pca)\
    __attribute__ ((weak, alias("empty_fn")));


int icc_status( uint8_t *status, int *status_len )\
    __attribute__ ((weak, alias("empty_fn")));
int icc_power_up( int cardno, uint8_t *out, int *outlen )\
    __attribute__ ((weak, alias("empty_fn")));
int icc_send_apdu( int cardno, uint8_t* in, int inlen, uint8_t *out, int *outlen )\
    __attribute__ ((weak, alias("empty_fn")));
int icc_power_down( int cardno )\
    __attribute__ ((weak, alias("empty_fn")));

int sec_pin_encrypt( pin_block_type_t format, sec_pin_encrypt_t *info, 
														uint8_t * result)\
    __attribute__ ((weak, alias("empty_fn")));
int sec_get_keygrp_no( uint8_t *fid, uint8_t *gid )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_set_curr_keygrp( uint8_t fid, uint8_t gid )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_crl_injection( void )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_key_injection( void )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_track_encrypt( uint8_t *track_bcd, int len )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_mac_dc_ecb(uint8_t* in, int len, uint8_t *out)\
    __attribute__ ((weak, alias("empty_fn")));

int get_curr_key( uint8_t type, uint8_t *out, uint32_t *outlen )\
    __attribute__ ((weak, alias("empty_fn")));
int set_des_key(uint8_t fid, uint8_t gid, uint8_t type, 
				uint8_t *in, uint32_t inlen, int allow_dup )\
    __attribute__ ((weak, alias("empty_fn")));
int get_des_key(  uint8_t fid, uint8_t gid, uint8_t type, 
				uint8_t *out, uint32_t *outlen )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_unset_key( uint8_t fid, uint8_t gid, uint8_t type )\
    __attribute__ ((weak, alias("empty_fn")));
int  sec_set_workkey( uint8_t fid, uint8_t gid, 
                            uint8_t type, sec_set_workkey_t *key_info )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_set_masterkey( uint8_t gid, sec_set_masterkey_t *key_info )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_update_masterkey( uint8_t gid, upt_masterkey_t *key_info )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_mac_9606(uint8_t* in, uint32_t len, uint8_t *out)\
    __attribute__ ((weak, alias("empty_fn")));
int sec_mac_x99(uint8_t* in, uint32_t len, uint8_t *out)\
    __attribute__ ((weak, alias("empty_fn")));
int sec_mac_x919(uint8_t* in, uint32_t len, uint8_t *out)\
    __attribute__ ((weak, alias("empty_fn")));
int sec_sm2_verify_signature( sm2_sign_t *sign, sm2_para_t *para )\
    __attribute__ ((weak, alias("empty_fn")));
int sec_sm3_calc( uint8_t *in, int len, uint8_t *out )\
    __attribute__ ((weak, alias("empty_fn")));

int prn_start(void)\
    __attribute__ ((weak, alias("empty_fn")));
void prn_putch(char ch, char **pca)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_set_font(hz_font_em hz_font, zm_font_em zm_font)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_set_underline(uint8_t pstatus)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_set_spacing(int border, int column, int row)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_set_grey(uint8_t grey)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_get_status( prn_status_em *status)\
    __attribute__ ((weak, alias("empty_fn")));
int prn_image(int x_size, int y_size, int x_pos, const char *img)\
    __attribute__ ((weak, alias("empty_fn")));
int  prn_init(void)\
    __attribute__ ((weak, alias("empty_fn")));
int sys_sleep(int sleep, void *flush_func, int flush_time)\
    __attribute__ ((weak, alias("empty_fn")));

int modem_get_sq(void)\
    __attribute__ ((weak, alias("empty_fn")));       
int modem_get_info(modem_info_em type, char *info)\
    __attribute__ ((weak, alias("empty_fn")));
int modem_get_station_info(modem_station_info_t *info)\
    __attribute__ ((weak, alias("empty_fn")));
int tcp_open(tcp_dev_em type)\
    __attribute__ ((weak, alias("empty_fn")));
int tcp_close( int fd)\
    __attribute__ ((weak, alias("empty_fn")));
int tcp_connect( int fd, const char *ip, int port, int timeout)\
    __attribute__ ((weak, alias("empty_fn")));
int tcp_write( int fd, const char* data, int data_len, int timeout)\
    __attribute__ ((weak, alias("empty_fn")));
int tcp_read(int fd, char* buf, int req_len, int timeout)\
    __attribute__ ((weak, alias("empty_fn")));
int sys_read_battery_status(uint32_t *voltage, uint8_t *level, 
                        uint32_t *button_vol)\
    __attribute__ ((weak, alias("empty_fn")));
int voice_ctrl_volume(uint32_t vol)__attribute__ ((weak, alias("empty_fn")));
int voice_file_play(char * pszFile)__attribute__ ((weak, alias("empty_fn")));
int sys_pm_ctrl(int onoff)__attribute__ ((weak, alias("empty_fn")));



extern void buzzer_start(void);
extern void buzzer_stop(void);
extern void led_ctrl(uint32_t nr, uint32_t on);
extern int nv_write(uint32_t offset, uint8_t * buf, int buflen);
extern int nv_read(uint32_t offset, uint8_t * buf, int buflen);
extern uint32_t security_status(void);


#ifdef CONFIG_MMU
/* File Operation */
RX_API_DEFINED(int, open)(const char *pathname, int oflag, ... /* mode_t mode */);
RX_API_DEFINED(int, close)(int fd);
RX_API_DEFINED(ssize_t, read)(int fd, void * buffer, size_t len);
RX_API_DEFINED(ssize_t, write)(int fd, const void * buffer, size_t len);
RX_API_DEFINED(int, select)(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);
RX_API_DEFINED(off_t, lseek)(int fd, off_t offset, int whence);
RX_API_DEFINED(int, truncate)(int fd, off_t lenght);
RX_API_DEFINED(int, unlink)(const char * pathname);
RX_API_DEFINED(int, ioctl)(int fd, int cmd, void *arg);

/* Time & Date Operation */
RX_API_DEFINED(int, gettimeofday)(struct timeval *tv, struct timezone *tz);
RX_API_DEFINED(int, settimeofday)(const struct timeval *tv , const struct timezone *tz);

/* LCD API */
RX_API_DEFINED(void, lcd_set_attribute)(uint8_t atr, void * arg);
RX_API_DEFINED(void, lcd_backlight)(uint32_t onff);
RX_API_DEFINED(void, lcd_clrscr)(void);
RX_API_DEFINED(int, lcd_disp_img)(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t * img);
RX_API_DEFINED(int, lcd_disp_string)(uint32_t x, uint32_t y, char * string);
RX_API_DEFINED(int, lcd_disp_hline)(uint32_t x, uint32_t y, uint32_t w);
RX_API_DEFINED(int, lcd_disp_vline)(uint32_t x, uint32_t y, uint32_t h);

RX_API_DEFINED(int, lcd_get_type)(void);
RX_API_DEFINED(int, lcd_push)(void);
RX_API_DEFINED(int, lcd_pop)(void);
RX_API_DEFINED(int, lcd_clrscr_line)(uint32_t start_y, uint32_t end_y);
RX_API_DEFINED(int, lcd_goto_xy)(uint32_t x, uint32_t y);
RX_API_DEFINED(int, lcd_get_xy)(uint32_t *px, uint32_t *py);
RX_API_DEFINED(int, lcd_set_view_port)(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
RX_API_DEFINED(int, lcd_get_view_port)(uint32_t *px, uint32_t *py, uint32_t *pw, uint32_t *ph);
RX_API_DEFINED(void,lcd_putch)(char ch, char **pca);
RX_API_DEFINED(int, lcd_set_font)(lcd_font_type_em emtype);
RX_API_DEFINED(int, lcd_set_space)(uint32_t wspace, uint32_t hspace);
RX_API_DEFINED(int, lcd_get_size)(uint32_t * pwidth, uint32_t * pheight);
RX_API_DEFINED(int, lcd_set_contrast)(uint32_t contrast);
RX_API_DEFINED(int, lcd_statusbar)(lcd_statusbar_em  new_flag, lcd_statusbar_em  *pold_flag);

RX_API_DEFINED(int, sys_cpufreq_notify_transition)(unsigned long freq,  void *data);
RX_API_DEFINED(int, sys_pm_ctrl)(int onoff);

/* Keypad Utility */
RX_API_DEFINED(int, kb_get_key)(int ms);
RX_API_DEFINED(int, kb_get_str)(char * input, int in_len, 
                                int min_len, int max_len, 
                                int timeout, char show, int mode);
RX_API_DEFINED(int, kb_get_amount)(char * amount, int max_len, int timeout);


/* POS Entry */
RX_API_DEFINED(int, pos_entry)(pos_entry_t entry, pos_entry_un *data, int ms);


RX_API_DEFINED(int, serial_init)(uint32_t id, serial_info_t * info);
RX_API_DEFINED(int, serial_write)(uint32_t id, uint8_t * buffer, size_t len);
RX_API_DEFINED(int, serial_read)(uint32_t id, uint8_t * buffer, size_t len, int timeout);
RX_API_DEFINED(int, serial_clrbuf)(uint32_t id, int rx, int tx);

RX_API_DEFINED(int, icc_status)( uint8_t *status, int *status_len );
RX_API_DEFINED(int, icc_power_up)( int cardno, uint8_t *out, int *outlen );
RX_API_DEFINED(int, icc_send_apdu)( int cardno, uint8_t* in, int inlen, uint8_t *out, int *outlen );
RX_API_DEFINED(int, icc_power_down)( int cardno );

/* voice*/
RX_API_DEFINED(int, voice_ctrl_volume)(uint32_t vol);
RX_API_DEFINED(int, voice_file_play)(char * pszFile);

/* Crypto */
RX_API_DEFINED(void, sha1_starts)(void);
RX_API_DEFINED(void, sha1_update)(uint8_t *input, int ilen);
RX_API_DEFINED(void, sha1_finish)(uint8_t output[20]);
RX_API_DEFINED(int,  sha2_starts)(int is224);
RX_API_DEFINED(void, sha2_update)(uint8_t * input, uint32_t length);
RX_API_DEFINED(void, sha2_finish)(uint8_t digest[32]);
RX_API_DEFINED(int, deskey)(uint8_t key[8], int decrypt);
RX_API_DEFINED(int, des)(uint8_t block[8], uint8_t output[8]);
RX_API_DEFINED(int, des3key2)(uint8_t key[16], int decrypt);
RX_API_DEFINED(int, des3key3)(uint8_t key[24], int decrypt);
RX_API_DEFINED(int, des3)(uint8_t block[8], uint8_t output[8]);

RX_API_DEFINED(uint8_t, rng_get_byte)(void);
RX_API_DEFINED(int, rng_get_string)(uint8_t * buf, uint32_t len);
RX_API_DEFINED(uint16_t, crc16)(uint16_t crc, uint8_t *buffer, uint32_t len);
RX_API_DEFINED(uint16_t, crc16_itu_t)(uint16_t crc, uint8_t *buffer, uint32_t len);
RX_API_DEFINED(uint32_t, crc32)(uint32_t crc, uint8_t *buffer, uint32_t len);

/*PCI key*/
RX_API_DEFINED(int, sec_key_injection)( void );
RX_API_DEFINED(int, sec_crl_injection)( void );
RX_API_DEFINED(int, sec_get_keygrp_no)( uint8_t *fid, uint8_t *gid );
RX_API_DEFINED(int, sec_set_curr_keygrp)( uint8_t fid, uint8_t gid );
RX_API_DEFINED(int, sec_set_workkey)( uint8_t fid, uint8_t gid, 
                    uint8_t type, sec_set_workkey_t *key_info );
RX_API_DEFINED(int, sec_unset_key)( uint8_t fid, uint8_t gid, uint8_t type );
RX_API_DEFINED(int, sec_set_masterkey)( uint8_t gid, sec_set_masterkey_t *key_info );
RX_API_DEFINED(int, sec_update_masterkey)( uint8_t gid, upt_masterkey_t *key_info );
RX_API_DEFINED(int, sec_pin_encrypt)( pin_block_type_t format, sec_pin_encrypt_t *info, 
							uint8_t * result);
RX_API_DEFINED(int, sec_mac_9606)(uint8_t* in, uint32_t len, uint8_t *out);
RX_API_DEFINED(int, sec_mac_x99)(uint8_t* in, uint32_t len, uint8_t *out);
RX_API_DEFINED(int, sec_mac_x919)(uint8_t* in, uint32_t len, uint8_t *out);
RX_API_DEFINED(int, sec_track_encrypt)( char *track_bcd, int len );
RX_API_DEFINED(int, sec_mac_dc_ecb)(uint8_t* in, int len, uint8_t *out);
RX_API_DEFINED(int, rsapublicfunc)(uint8_t *output,uint32_t *outputLen,
                uint8_t *input, uint32_t inputLen,R_RSA_PUBLIC_KEY *publicKey );
RX_API_DEFINED(int, sec_sm2_verify_signature)( sm2_sign_t *sign, sm2_para_t *para );
RX_API_DEFINED(int, sec_sm3_calc)( uint8_t *in, int len, uint8_t *out );
/* Misc Operation */
RX_API_DEFINED(void, mdelay)(uint32_t ms);               /**< Delay Milliseconds */
RX_API_DEFINED(void, buzzer_start)(void);
RX_API_DEFINED(void, buzzer_stop)(void);
RX_API_DEFINED(void, led_ctrl)(uint32_t nr, uint32_t on);
RX_API_DEFINED(uint32_t, security_status)(void);
RX_API_DEFINED(int, nv_write)(uint32_t offset, uint8_t * buf, int buflen);
RX_API_DEFINED(int, nv_read)(uint32_t offset, uint8_t * buf, int buflen);
RX_API_DEFINED(int, sys_get_param)(uint32_t type, void *buf, uint32_t len);
RX_API_DEFINED(int, sys_set_param)(uint32_t type, void *buf, uint32_t len);

/* Code Utility */
RX_API_DEFINED(int, asc2bcd)(char * ascstr, int len, uint8_t *bcdstr, int align);
RX_API_DEFINED(int, bcd2asc)(uint8_t * bcd, int asclen, char * asc, int align);

/* Module Library */
RX_API_DEFINED(void *, sys_load_library)(char *name);
RX_API_DEFINED(int, sys_run_app)(char *name);
RX_API_DEFINED(int, sys_update_mod)(mod_update_t *update, uint8_t nr);

/*timeout*/
RX_API_DEFINED(uint32_t, timeout_start)(void);
RX_API_DEFINED(uint32_t, timeout_test)(uint32_t *start, uint32_t *ms);
RX_API_DEFINED(void, reset)(void);

RX_API_DEFINED(int, prn_start)(void);
RX_API_DEFINED(int, prn_string)( const char *str, ... );
RX_API_DEFINED(int, prn_set_font)(hz_font_em hz_font, zm_font_em zm_font);
RX_API_DEFINED(int, prn_set_underline)(uint8_t pstatus);
RX_API_DEFINED(int, prn_set_spacing)(int border, int column, int row);
RX_API_DEFINED(int, prn_set_grey)(uint8_t grey);
RX_API_DEFINED(int, prn_get_status)( prn_status_em *status);
RX_API_DEFINED(int, prn_image)(int x_size, int y_size, int x_pos, const char *img);
RX_API_DEFINED(int,  prn_init)(void);

RX_API_DEFINED(int, sys_sleep)(int sleep, void *flush_func, int flush_time);
RX_API_DEFINED(int, sys_read_battery_status)(uint32_t *voltage, uint8_t *level,
                                            uint32_t *button_vol);

#endif


const sys_api_t sys_api = {
        .open = __GET_API(open),
        .close = __GET_API(close),   
        .read = __GET_API(read),
        .write = __GET_API(write),
        .select = __GET_API(select),
        .lseek = __GET_API(lseek),
        .truncate = __GET_API(truncate),
        .unlink = __GET_API(unlink),
        .ioctl = __GET_API(ioctl),

        /* LCD */
        .lcd_set_attribute = __GET_API(lcd_set_attribute),
        .lcd_backlight = __GET_API(lcd_backlight),
        .lcd_clrscr = __GET_API(lcd_clrscr),
        .lcd_disp_img = __GET_API(lcd_disp_img),
        .lcd_disp_string = __GET_API(lcd_disp_string),
        .lcd_disp_hline = __GET_API(lcd_disp_hline),
        .lcd_disp_vline = __GET_API(lcd_disp_vline),

        .lcd_get_type = __GET_API(lcd_get_type),
        .lcd_push = __GET_API(lcd_push),
        .lcd_pop = __GET_API(lcd_pop),
        .lcd_clrscr_line = __GET_API(lcd_clrscr_line),
        .lcd_goto_xy = __GET_API(lcd_goto_xy),
        .lcd_get_xy = __GET_API(lcd_get_xy),
        .lcd_set_view_port = __GET_API(lcd_set_view_port),
        .lcd_get_view_port = __GET_API(lcd_get_view_port),
        .lcd_putch = __GET_API(lcd_putch),
        .lcd_set_font = __GET_API(lcd_set_font),
        .lcd_clrscr_line = __GET_API(lcd_clrscr_line),
        .lcd_set_space = __GET_API(lcd_set_space),
        .lcd_get_size = __GET_API(lcd_get_size),
        .lcd_backlight = __GET_API(lcd_backlight),
        .lcd_set_contrast = __GET_API(lcd_set_contrast),
        .lcd_statusbar = __GET_API(lcd_statusbar),
        
        .kb_get_key = __GET_API(kb_get_key),
        .kb_get_str = __GET_API(kb_get_str),
        .kb_get_amount = __GET_API(kb_get_amount),
        
        .pos_entry = __GET_API(pos_entry),

        /* Serial */
        .serial_init = __GET_API(serial_init),
        .serial_write = __GET_API(serial_write),
        .serial_read = __GET_API(serial_read),
        .serial_clrbuf = __GET_API(serial_clrbuf),
        /* ICC */
        .icc_status = __GET_API(icc_status),
        .icc_power_up = __GET_API(icc_power_up),
        .icc_send_apdu = __GET_API(icc_send_apdu),
        .icc_power_down = __GET_API(icc_power_down),

        .voice_ctrl_volume = __GET_API(voice_ctrl_volume),
        .voice_file_play = __GET_API(voice_file_play),
        
        .sha1_starts = __GET_API(sha1_starts),
        .sha1_update = __GET_API(sha1_update),
        .sha1_finish = __GET_API(sha1_finish),
        .sha2_starts = __GET_API(sha2_starts),
        .sha2_update = __GET_API(sha2_update),
        .sha2_finish = __GET_API(sha2_finish),
        .deskey = __GET_API(deskey),
        .des = __GET_API(des),
        .des3key2 = __GET_API(des3key2),
        .des3key3 = __GET_API(des3key3),
        .des3 = __GET_API(des3),
        
        .rng_get_byte = __GET_API(rng_get_byte),
        .rng_get_string = __GET_API(rng_get_string),

        .crc16 = __GET_API(crc16),
        .crc16_itu_t = __GET_API(crc16_itu_t),
        .crc32 = __GET_API(crc32),
		.rsapublicfunc =  __GET_API(rsapublicfunc), 
		/* PCI key */
		.sec_key_injection =  __GET_API(sec_key_injection),
		.sec_crl_injection =  __GET_API(sec_crl_injection),
		.sec_get_keygrp_no =  __GET_API(sec_get_keygrp_no),
		.sec_set_curr_keygrp =  __GET_API(sec_set_curr_keygrp),
		.sec_set_workkey = __GET_API(sec_set_workkey),
		.sec_unset_key = __GET_API(sec_unset_key),
		.sec_set_masterkey = __GET_API(sec_set_masterkey),
		.sec_update_masterkey = __GET_API(sec_update_masterkey), 
		.sec_pin_encrypt =  __GET_API(sec_pin_encrypt),
		.sec_mac_9606 =  __GET_API(sec_mac_9606),
		.sec_mac_x99 =  __GET_API(sec_mac_x99),
		.sec_mac_x919 =  __GET_API(sec_mac_x919),
		.sec_track_encrypt =  __GET_API(sec_track_encrypt),
		.sec_mac_dc_ecb = __GET_API(sec_mac_dc_ecb),
        .sec_sm2_verify_signature = __GET_API(sec_sm2_verify_signature),
		.sec_sm3_calc = __GET_API(sec_sm3_calc),


        .mdelay = __GET_API(mdelay),
        .gettimeofday = __GET_API(gettimeofday),
        .settimeofday = __GET_API(settimeofday),
		.timeout_start = __GET_API(timeout_start),
		.timeout_test = __GET_API(timeout_test),
		
        .buzzer_start = __GET_API(buzzer_start),
        .buzzer_stop = __GET_API(buzzer_stop),
        
        .led_ctrl = __GET_API(led_ctrl),
        
        .security_status = __GET_API(security_status),
        .nv_write = __GET_API(nv_write),
        .nv_read = __GET_API(nv_read),
        
        .asc2bcd = __GET_API(asc2bcd),
        .bcd2asc = __GET_API(bcd2asc),
			
        .sys_load_library = __GET_API(sys_load_library),
        .sys_run_app = __GET_API(sys_run_app),
        .sys_get_param = __GET_API(sys_get_param),
        .sys_set_param = __GET_API(sys_set_param),
        .sys_update_mod = __GET_API(sys_update_mod),
        .reset = __GET_API(reset),
		.sys_cpufreq_notify_transition = __GET_API(sys_cpufreq_notify_transition),
            
		.modem_get_sq = __GET_API(modem_get_sq),
		.modem_get_info = __GET_API(modem_get_info),
		.modem_get_station_info = __GET_API(modem_get_station_info),
		
		.tcp_open = __GET_API(tcp_open),
		.tcp_close = __GET_API(tcp_close),
		.tcp_connect = __GET_API(tcp_connect),
		.tcp_write = __GET_API(tcp_write),
		.tcp_read = __GET_API(tcp_read),
		
		/* Printer */
		.prn_start = __GET_API(prn_start),
		.prn_putch = __GET_API(prn_putch),
		.prn_string = __GET_API(prn_string),
		.prn_set_font = __GET_API(prn_set_font),
		.prn_set_underline = __GET_API(prn_set_underline),
		.prn_set_spacing = __GET_API(prn_set_spacing),
		.prn_set_grey = __GET_API(prn_set_grey),
		.prn_get_status = __GET_API(prn_get_status),
		.prn_image = __GET_API(prn_image),
		.prn_init = __GET_API(prn_init),
		
        .sys_sleep = __GET_API(sys_sleep),
        .sys_read_battery_status = __GET_API(sys_read_battery_status),
        .sys_pm_ctrl = __GET_API(sys_pm_ctrl),

};

module_t * load_module(char *name)
{
	part_t * part;
	module_t * pmod;
    if (name == NULL) return NULL;
	if ((part = get_part_by_name(name, NULL)) == NULL) {
		if ((part = get_sys_mods_by_name(name, 0, 0, 0)) == NULL) {
		    return NULL;

        }
	}

	if (!(part->flags & PART_TYPE_MOD)) {
	        return NULL;
     }
    if (!verify_firmware2(part)) {
        return NULL;
    }

	pmod = (module_t *)(part_base(part) + MAX_RSA_MODULUS_LEN);

	if (pmod->magic_num != MODULE_MAGIC) {
        return NULL;
    }
	uint32_t *psrc, *pdest;
	psrc = (uint32_t *)(pmod->text_end);
	for(pdest = (uint32_t *)(pmod->data_start);
			pdest < (uint32_t *)(pmod->data_end); ) {
		*(pdest ++) = *(psrc ++);
	}

	for(pdest = (uint32_t *)(pmod->bss_start);
		    pdest < (uint32_t *)(pmod->bss_end); ) {
		*(pdest ++) = 0;
	}

	// switch to user mode and startup user application
	user_mode();
	pmod->module_init((sys_api_t *)&sys_api);
	// return to KERNEL mode!
	kernel_mode();
	return pmod;
}

void * sys_load_library(char *name)
{
	module_t * pmod = load_module(name);
	if (pmod == NULL) return NULL;

	// switch to user mode and startup user application
	user_mode();
	void *p = pmod->module_export();
	// return to KERNEL mode!
	kernel_mode();
	return p;
}

int sys_run_app(char *name)
{
	int ret;
	module_t * pmod = load_module(name);
	if (pmod == NULL) {
        return -1;
    }

	// switch to user mode and startup user application
	user_mode();
	ret = pmod->module_main();
	// return to KERNEL mode!
	kernel_mode();
	return ret;
}
#ifdef RUN_ADRESS_APP
int run_selfapp(char *name)
{
#define Len 256

	int ret;
	part_t * part;
	uint8_t buf[Len];
	uint32_t offset = MAX_RSA_MODULUS_LEN; //filter MAX_RSA_MODULUS_LEN
    volatile uint8_t *p = (volatile uint8_t *)Selftest_Adrress;
	volatile module_t * pdmod = (volatile module_t *)Selftest_Adrress;

    if (name == NULL) return NULL;
	if ((part = get_part_by_name(name, NULL)) == NULL) {
		if ((part = get_sys_mods_by_name(name, 0, 0, 0)) == NULL)
		    return NULL;
	}

	if (!(part->flags & PART_TYPE_MOD))
	        return NULL;

	if (!verify_firmware2(part)) return NULL;
	
    while (part_read(part, offset, buf, Len)) {
		memcpy(p, buf, Len);
		p+= Len;
		offset += Len;
		if (offset > part->size)break;
    }
	
	if (pdmod->magic_num != MODULE_MAGIC) return NULL;

    pdmod->module_init((sys_api_t *)&sys_api);

	user_mode();
	ret = pdmod->module_main();	
	kernel_mode();
	
	return ret;
}
#endif
